package com.kuzmich.locator.location;

import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;

import android.content.Context;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;

public class MyGPSProvider implements MyLocationProvider
{
	static private final String TAG = "MyGPSProvider";
	/* 3 minutes */
	static private final long MIN_DELAY_TO_KEEP_GPS_ON = 3 * 60 * 1000;

	private LocationManager lm;
	private Context ctx;
	private Timer timer;
	private boolean enabled = true;
	private Map<LocationListener, LocationPollTask> polledTasks;

	private class LocationPollTask extends TimerTask
	{
		private LocationListener listener;

		public LocationPollTask(LocationListener listener)
		{
			this.listener = listener;
		}

		@Override
		public void run()
		{
			lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 10, 0,
				new LocationListener()
		  	{
					public void onStatusChanged(String provider, int status, Bundle extras)
					{
						// TODO Auto-generated method stub
					}

					public void onProviderEnabled(String provider)
					{
						// TODO Auto-generated method stub
					}

					public void onProviderDisabled(String provider)
					{
						// TODO Auto-generated method stub
					}

					public void onLocationChanged(Location location)
					{
						/* Once a location is reported, the listener remove itself fromm GPS
						 * provider to turn off the GPS.
						 */
						listener.onLocationChanged(location);
						lm.removeUpdates(this);
					}
		  	});

			log("Location poll task is being run. Enabling GPS");
		}
	}

	public MyGPSProvider(Context ctx)
  {
		this.ctx = ctx;
		this.timer = new Timer();
		this.polledTasks = new HashMap<LocationListener, LocationPollTask>();
		this.lm = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE);
  }

	public Location getLastKnownLocation()
  {
		return lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
  }

	public boolean isEnabled()
  {
		/* If GPS was forced disabled by setEnabled function, return false.
		 * Else check its real state.
		 */
		if (!enabled)
			return false;

		return lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
  }

	public boolean meetsCriteria(Criteria criteria)
  {
		return lm.getProvider(LocationManager.GPS_PROVIDER)
		  .meetsCriteria(criteria);
  }

	public void removeUpdates(LocationListener listener)
  {
		LocationPollTask task = null;

		if ((task = polledTasks.get(listener)) != null)
		{
			task.cancel();
			polledTasks.remove(listener);
		}
		lm.removeUpdates(listener);
  }

	public void requestLocationUpdates(long minTime, float minDistance,
    LocationListener listener)
  {
		if (minTime > MIN_DELAY_TO_KEEP_GPS_ON)
		{
			LocationPollTask task = null;

			log("delay is too big. I'll switch GPS on and off each time");
			/* XXX: Currently, for each listener has a single task. Thus, if a given
			 * listener already has one, cancel it */
			if ((task = polledTasks.get(listener)) != null)
			{
				task.cancel();
				polledTasks.remove(listener);
			}

			task = new LocationPollTask(listener);
			polledTasks.put(listener, task);
			timer.schedule(task, minTime);
			return;
		}

		lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, listener);
  }

	/**
	 * Send a message to the log. It is added more for debug purposes than for
	 * log ones.
	 * @param msg a log message
	 */
	private void log(String msg)
	{
		Log.v(TAG, msg);
	}

	public void setEnabled(boolean enabled)
  {
		this.enabled = enabled;
  }

}